﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace Prsrp
{
    /// <summary>
    /// This class implements a visual element in the game.
    /// By design, we take in consideration that anything drawable is managable.
    /// </summary>
    /// <remarks>
    /// Each class who herit from BaseDisplayable must redefine the following functions:
    /// . LoadSprites()
    /// . Draw()
    /// </remarks>
    public class BaseDisplayable : BaseStateMachine
    {
        #region Properties

        // Position Vector
        public Vector2 mvPos = new Vector2(0, 0);

        // Size Vector
        public Vector2 mvSize;

        // Scale
        public float mfScale = 2;

        // Display Variables
        public bool mbFlipSprite = false;

        // Sprites
        public List<Animation> mtabStateSprites = new List<Animation>();

        #endregion

        #region Methods & Functions

        protected void DefineSprite(object _StateIndex, Animation _pAnimation)
        {
            int iStateIndex = (int)_StateIndex;

            // Resize List if needed.
            while (iStateIndex > mtabStateSprites.Count) mtabStateSprites.Add(null);

            // Insert Content
            mtabStateSprites.Insert(iStateIndex, _pAnimation);
        }

        protected void DefineSprite(object _StateIndex, String _sSpritePath, int _iNbOfFrames)
        {
            Animation pNewAnim = new Animation(Game.Instance.Content.Load<Texture2D>(_sSpritePath) as Texture2D, _iNbOfFrames);
            DefineSprite(_StateIndex, pNewAnim);
        }

        public int GetWidth()
        {
            return (int)(mvSize.X * mfScale);
        }

        public int GetHeight()
        {
            return (int)(mvSize.Y * mfScale);
        }

        /// <return>
        /// Return the current hitbox of the asset.
        /// </return>
        public Rectangle GetHitBox()
        {
            int iWidth = GetWidth();
            int iHeight = GetHeight();
            return new Rectangle((int)mvPos.X, (int)(mvPos.Y - iWidth / 2.0f), iWidth, iHeight);
        }

        /// <return>
        /// Return the hitbox if the asset is at a position of @_vPos.
        /// </return>
        public Rectangle GetHitBox(Vector2 _vPos)
        {
            int iWidth = GetWidth();
            int iHeight = GetHeight();
            return new Rectangle((int)_vPos.X, (int)(_vPos.Y - iWidth / 2.0f), iWidth, iHeight);
        }

        public bool IntersectHitBox(Vector2 _vPos)
        {
            Rectangle pCurHitBox = GetHitBox();
            return pCurHitBox.Contains((int)_vPos.X, (int)_vPos.Y);
        }

        /// <returns>
        /// Return true if the BaseAsset is outside of the screen.
        /// </returns>
        /// <remarks>
        /// For now it only check for horizontal bounds.
        /// Todo: Redo with camera support.
        /// </remarks>
        public bool IsOutOfScreen()
        {
            Rectangle pHitBox = GetHitBox();
            return ((pHitBox.Left + pHitBox.Width < 0) || (pHitBox.Right - pHitBox.Width > GameGlobals.GameWidth));
        }

        #endregion

        #region Pure Virtual Methods

        /// <summary>
        /// This function will load the ressources needed by the class.
        /// Since it use the Game ContentManager, there should not be any waste of memory.
        /// </summary>
        public virtual void LoadSprites() { throw new NotImplementedException(); }

        /// <summary>
        /// This function provite a basic draw method for displayable sprites.
        /// </summary>
        public virtual void Draw()
        {
            mtabStateSprites[0].Draw(mvPos, mfScale, mbFlipSprite);
        }

        #endregion
    }
}
